package org.momonga1banchi.reminder.util;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日付ユーティリティー
 * 
 * @author momonga1banchi
 * 
 */
public class DateUtil {

    private static Logger log = Logger.getLogger(DateUtil.class.getName());

    static {
        TimeZone tokyoTime = TimeZone.getTimeZone("JST");
        Calendar calendar = Calendar.getInstance(tokyoTime);
        calendar.add(Calendar.HOUR_OF_DAY, 9);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        log.info("os=" + System.getProperty("os.name") + " " + year + "/" + month + "/" + day + " " + " " + hour + ":"
                + minute + ":" + second);

    }

    /**
     * メール件名からリマインド時刻を生成
     * 
     * <pre>
     * 今のところ対象にしているのは
     * 月日時分８桁の数字（MMDDhhmm）
     * 時分４桁の数字（hhmm）
     * 
     * </pre>
     * 
     * @param input
     * @return リマインド時刻
     */
    public static Calendar makeRemindDate(String input) {
        Calendar remindDate = getDateByNum(input);
        if (remindDate == null)
            remindDate = getDateByJapanese(input);
        return remindDate;
    }

    /**
     * 日本語入力からリマインド時刻を生成する。
     * 
     * @param input
     * @return リマインド時刻
     */
    public static Calendar getDateByJapanese(String input) {
        TimeZone tokyoTime = TimeZone.getTimeZone("JST");
        Calendar calendar = Calendar.getInstance(tokyoTime);
        calendar.add(Calendar.HOUR_OF_DAY, 9);

        // 日付調整用変数。　年、月、日、時、分を表す。それぞれの値の増減を行う。
        int[] dateAdjuster = { 0, 0, 0, 0, 0 };
        // 日付調整実施
        if (input != null) {
            // 月の調整
            if (input.contains("来月")) {
                dateAdjuster[1] = 1;
            }
            // TODO 日の調整 ・・・　曜日（月〜日）指定の設定も後ほど行う。
            if (input.contains("明日")) {
                dateAdjuster[2] = 1;
            } else if (input.contains("明後日")) {
                dateAdjuster[2] = 2;
            } else if (input.contains("来週")) {
                dateAdjuster[2] = 7;
            }
            // 時の調整
            Pattern hourPattern = Pattern.compile("([0-9０-９]{1,2})時間[^後]*後");
            Matcher hourMatcher = hourPattern.matcher(input);
            if (hourMatcher.find()) {
                String hour = hourMatcher.group(1);
                hour.replaceAll("０", "0").replaceAll("１", "1").replaceAll("２", "2").replaceAll("３", "3").replaceAll(
                        "４", "4").replaceAll("５", "5").replaceAll("６", "6").replaceAll("７", "7").replaceAll("８", "8")
                        .replaceAll("９", "9");
                dateAdjuster[3] = Integer.valueOf(hour);
            }
            // 分の調整
            Pattern minutePattern = Pattern.compile("([0-9０-９]{1,3})分後");
            Matcher minuteMatcher = minutePattern.matcher(input);
            if (minuteMatcher.find()) {
                String minute = minuteMatcher.group(1);
                minute.replaceAll("０", "0").replaceAll("１", "1").replaceAll("２", "2").replaceAll("３", "3").replaceAll(
                        "４", "4").replaceAll("５", "5").replaceAll("６", "6").replaceAll("７", "7").replaceAll("８", "8")
                        .replaceAll("９", "9");
                dateAdjuster[4] = Integer.valueOf(minute);
            }

            // 調整時刻を設定
            calendar.add(Calendar.MONTH, dateAdjuster[1]);
            calendar.add(Calendar.DAY_OF_MONTH, dateAdjuster[2]);
            calendar.add(Calendar.HOUR_OF_DAY, dateAdjuster[3]);
            calendar.add(Calendar.MINUTE, dateAdjuster[4]);

        } else {
            // 時刻指定がない場合、デフォルトで１５分後にリマインド設定する。
            calendar.add(Calendar.MINUTE, 15);
        }
        return calendar;
    }

    /**
     * 文字列が8桁、もしくは4桁の数値のみの場合にリマインド時刻を生成する。
     * 
     * <pre>
     * 対象時刻が現在時刻よりも過去の場合、月から指定した場合は翌年、
     * 時刻から指定した場合は翌日の時刻がリマインド時刻となる。
     * </pre>
     * 
     * @param input
     * @return リマインド時刻
     */
    public static Calendar getDateByNum(String input) {
        if (input == null || input.equals(""))
            return null;
        input = input.replaceAll("０", "0").replaceAll("１", "1").replaceAll("２", "2").replaceAll("３", "3").replaceAll(
                "４", "4").replaceAll("５", "5").replaceAll("６", "6").replaceAll("７", "7").replaceAll("８", "8")
                .replaceAll("９", "9");

        Pattern timePattern = Pattern.compile("([0-9]{4})");
        Matcher timeMatcher = timePattern.matcher(input);
        String time = null;
        Pattern datePattern = Pattern.compile("([0-9]{8})");
        Matcher dateMatcher = datePattern.matcher(input);
        String date = null;
        if (dateMatcher.matches()) {
            date = dateMatcher.group(1);
        } else if (timeMatcher.matches()) {
            time = timeMatcher.group(1);
        } else {
            return null;
        }

        TimeZone tokyoTime = TimeZone.getTimeZone("JST");
        Calendar calendar = Calendar.getInstance(tokyoTime);
//        calendar.add(Calendar.HOUR_OF_DAY, 9);    // not required

        DecimalFormat formatter2d = new DecimalFormat("00");
        String now = formatter2d.format(calendar.get(Calendar.YEAR) - 2000)
                + formatter2d.format(calendar.get(Calendar.MONTH) + 1)
                + formatter2d.format(calendar.get(Calendar.DAY_OF_MONTH))
                + formatter2d.format(calendar.get(Calendar.HOUR_OF_DAY))
                + formatter2d.format(calendar.get(Calendar.MINUTE));
        log.info("162: " + now);

        try {
            if (date != null) {
                DateFormat dbDateformat = new SimpleDateFormat("yyMMddHHmm");
                String remindDate = formatter2d.format(calendar.get(Calendar.YEAR) - 2000) + date;

                Date selectedDate = null;
                if (Integer.valueOf(now) - Integer.valueOf(remindDate) > 0) {
                    selectedDate = dbDateformat
                            .parse(formatter2d.format(calendar.get(Calendar.YEAR) - 2000 + 1) + date);
                } else {
                    selectedDate = dbDateformat.parse(remindDate);
                }
                calendar.setTime(selectedDate);
            } else if (time != null) {
                DateFormat dbDateformat = new SimpleDateFormat("yyMMddHHmm");

                String remindTime = formatter2d.format(calendar.get(Calendar.YEAR) - 2000)
                        + formatter2d.format(calendar.get(Calendar.MONTH) + 1)
                        + formatter2d.format(calendar.get(Calendar.DAY_OF_MONTH)) + time;
                log.info("183:  " + now + " ------ " + remindTime);

                Date selectedTime = null;
                if (Integer.valueOf(now) - Integer.valueOf(remindTime) > 0) {
                    calendar.add(Calendar.DAY_OF_MONTH, 1);
                    selectedTime = dbDateformat.parse(formatter2d.format(calendar.get(Calendar.YEAR) - 2000)
                            + formatter2d.format(calendar.get(Calendar.MONTH) + 1)
                            + formatter2d.format(calendar.get(Calendar.DAY_OF_MONTH)) + time);
                } else {
                    selectedTime = dbDateformat.parse(remindTime);
                }

                log.info(selectedTime.toString());
                calendar.setTime(selectedTime);
            }
            return calendar;
        } catch (NumberFormatException e) {
            log.warning(e.getMessage());
        } catch (ParseException e) {
            log.warning(e.getMessage());
        }
        return null;
    }
}
